﻿using System;
using System.Runtime.InteropServices;

namespace Project_CFT2.RFID
{
    /// <summary>
    /// RS232’ÊM—pƒNƒ‰ƒX
    /// </summary>
    /// 

    public class Rs232c
    {
        //ƒVƒŠƒAƒ‹ƒ|[ƒg‚ÌÝ’è‚É—˜—p‚·‚é\‘¢‘Ì
        private struct DCB
        {
            public int DCBLength;				//\‘¢‘Ì‚ÌƒTƒCƒY
            public int BaudRate;				//ƒ{[ƒŒƒCƒgibpsj‚ÌÝ’è
            public int fBitFields;				//ƒrƒbƒg’PˆÊ‚ÌƒtƒB[ƒ‹ƒh’è‹`
            public short wReserved;				//—\–ñi0‚ðƒZƒbƒg‚·‚éj
            public short XonLim;				//Xon•¶Žš‚ð‘—‚éƒoƒbƒtƒ@ƒoƒCƒg”‚ÌŽw’è
            public short XoffLim;				//Xoff•¶Žš‚ðƒoƒbƒtƒ@ƒoƒCƒg”‚ðŽw’è
            public byte ByteSize;				//1ƒf[ƒ^‚Ìƒrƒbƒg”‚ðŽw’è
            public byte Parity;					//ƒpƒŠƒeƒB‚Ì•ûŽ®‚ðŽw’è
            public byte StopBits;				//ƒXƒgƒbƒvƒrƒbƒg”‚ðŽw’è
            public byte XonChar;				//Xon•¶Žš‚ðŽw’è
            public byte XoffChar;				//Xoff•¶Žš‚ðŽw’è
            public byte ErrorChar;				//ƒpƒŠƒeƒBƒGƒ‰[‚Ìê‡‚ÉŽg‚¤•¶ŽšŽw’è
            public byte EofChar;				//”ñƒoƒCƒiƒŠƒ‚[ƒh‚Ìƒf[ƒ^I—¹
            public byte EvtChar;				//ƒCƒxƒ“ƒg‚ð¶¬‚·‚é•¶Žš‚ðŽw’è

        }
        //ƒ^ƒCƒ€ƒAƒEƒg‚ÌÝ’è‚É—˜—p‚·‚é\‘¢‘Ì
        private struct COMMTIMEOUTS
        {
            public int ReadIntervalTimeout;		//•¶Žš‚Ì“Ç‚Ýž‚Ý‚Ì‘Ò‚¿ŽžŠÔ
            public int ReadTotalTimeoutMultiplier;	//“Ç‚Ýž‚Ý‚Ì‚P•¶Žš‚ ‚½‚è‚ÌŽžŠÔ
            public int ReadTotalTimeoutConstant;	//“Ç‚Ýž‚Ý‚Ì’è”ŽžŠÔ
            public int WriteTotalTimeoutMultiplier;	//‘‚«ž‚Ý‚Ì‚P•¶Žš‚ ‚½‚è‚ÌŽžŠÔ
            public int WriteTotalTimeoutConstant;	//‘‚«ž‚Ý‚Ì’è”ŽžŠÔ
        }


        private DCB dcb;				//DCB\‘¢‘Ì‚ÌéŒ¾
        private COMMTIMEOUTS commTimeOuts;		//COMMTIMEOUTS\‘¢‘Ì‚ÌéŒ¾

        private int hComm;					//ƒnƒ“ƒhƒ‹—p•Ï”‚ÌéŒ¾
        private bool openFlag;

        private string port;
        private int baudRate;

        //ƒRƒ“ƒXƒgƒ‰ƒNƒ^
        public Rs232c(string port, int baudRate)
        {
            this.openFlag = false;
            this.port = port;
            this.baudRate = baudRate;
        }

        //ƒ|[ƒg”Ô†‚ðÝ’èEŽæ“¾
        public string Port
        {
            get { return this.port; }
            set { this.port = value; }
        }

        //ƒ|[ƒg‚Ìó‘Ô‚ðŽæ“¾
        public bool IsOpen
        {
            get { return this.openFlag; }
        }

        //ƒVƒŠƒAƒ‹ƒ|[ƒg‚ðŠJ‚­
        public unsafe bool Open()
        {
            const uint READ_WRITE = 0x80000000 | 0x40000000;		//“Ç‚Ý‘‚«—¼—p
            const uint OPEN_EXISTING = 3;

            //ƒ|[ƒg‚ðŠJ‚­
            hComm = CreateFile(port, READ_WRITE, 0, 0, OPEN_EXISTING, 0, 0);

            if (hComm == -1)
            {
                this.openFlag = false;
                return false;
            }

            //ƒVƒŠƒAƒ‹’ÊM‚ÌÝ’è
            dcb = new DCB();
            dcb.BaudRate = baudRate;							//“]‘—‘¬“x‚ÌŽw’è(9600bps)
            dcb.ByteSize = 8;									//ƒrƒbƒg’·‚ÌŽw’èi8ƒrƒbƒgj
            dcb.fBitFields = 0;									//ƒeƒLƒXƒgƒ‚[ƒhARTS§Œä‚È‚µ
            dcb.Parity = 0;										//ƒpƒŠƒeƒB‚ÌÝ’èiƒpƒŠƒeƒB‚È‚µj
            dcb.StopBits = 0;						            //ƒXƒgƒbƒvƒrƒbƒg”‚ðŽw’è(1ƒrƒbƒg)

            fixed (DCB* d = &dcb)
            {
                SetCommState(hComm, d);
            }

            //ƒ^ƒCƒ€ƒAƒEƒg‚ÌÝ’è
            commTimeOuts.ReadIntervalTimeout = 50;						//‘S•¶Žš‚Ì“Ç‚Ýž‚Ý‘Ò‚¿ŽžŠÔi50msj
            commTimeOuts.ReadTotalTimeoutMultiplier = 0;				//“Ç‚Ýž‚Ý‚Ì‚P•¶Žš‚ ‚½‚è‚Ì‘Ò‚¿ŽžŠÔ
            commTimeOuts.ReadTotalTimeoutConstant = 50;					//“Ç‚Ýž‚Ý‚ÌÅ¬‘Ò‚¿ŽžŠÔi50msj
            commTimeOuts.WriteTotalTimeoutMultiplier = 0;				//‘‚«ž‚Ý‚Ì‚P•¶Žš‚ ‚½‚è‚Ì‘Ò‚¿ŽžŠÔ
            commTimeOuts.WriteTotalTimeoutConstant = 50;				//‘‚«ž‚Ý‚ÌÅ¬‘Ò‚¿ŽžŠÔi50msj
            fixed (COMMTIMEOUTS* comm = &commTimeOuts)
            {
                SetCommTimeouts(hComm, comm);
            }
            this.openFlag = true;
            return true;
        }

        //ƒVƒ‹ƒAƒ‹ƒ|[ƒg‚ð•Â‚¶‚é
        public void Close()
        {
            CloseHandle(hComm);
            this.openFlag = false;
            return;
        }

        //ƒVƒŠƒAƒ‹ƒ|[ƒg‚Éƒf[ƒ^‚ð‘‚«o‚·
        public unsafe bool WriteBytes(byte[] txBytes)
        {
            byte[] txData = txBytes;
            bool txFlag;
            int txLen = 0;

            fixed (byte* p = txData)
            {
                txFlag = WriteFile(hComm, p, txData.Length, &txLen, 0);

                if (!(txFlag))
                {
                    return false;
                }
            }
            return true;
        }

        //ƒVƒŠƒAƒ‹ƒ|[ƒg‚©‚çƒf[ƒ^‚ð“Ç‚Ýž‚Þ
        public unsafe bool ReadBytes(ref byte[] rxBytes)
        {
            //ŽóMƒf[ƒ^
            byte[] rxData = new byte[rxBytes.Length];
            //ŽóM‚³‚ê‚½ƒf[ƒ^’·
            int rxLen = 0;
            //ReadFile‚Ì–ß‚è’l
            bool rxFlag;

            fixed (byte* p = rxData)
            {
                rxFlag = ReadFile(hComm, p, rxData.Length, &rxLen, 0);

                if (!(rxFlag))
                {
                    return false;
                }
            }
            if (rxLen == 0 || rxData[0] == 0)
                return false;

            rxBytes = rxData;
            return true;
        }

        #region DllImport‚ÌéŒ¾
        [DllImport("kernel32", SetLastError = true)]
        static extern unsafe int CreateFile(string lpFileName, uint dwDesiredAccess, uint dwShareMode,
            uint lpSecurityAttributes /*really SecurityAttributes pointer*/, uint dwCreationDisposition,
            uint dwFlagsAndAttributes, uint hTemplateFile);

        [DllImport("kernel32", SetLastError = true)]
        static extern unsafe bool ReadFile(int hFile, void* lpBuffer, int nBytesToRead, int* nBytesRead, int lpOverlapped);

        [DllImport("kernel32", SetLastError = true)]
        static extern unsafe bool WriteFile(int hFile, void* lpBuffer, int nBytesToWrite, int* nBytesWrite, int lpOverlapped);

        [DllImport("kernel32", SetLastError = true)]
        static extern unsafe int CloseHandle(int hObject);

        [DllImport("kernel32", SetLastError = true)]
        static extern unsafe int SetCommState(int hCommDev, DCB* lpDCB);

        [DllImport("kernel32", SetLastError = true)]
        static extern unsafe int SetCommTimeouts(int hCommDev, COMMTIMEOUTS* lpCommTimeouts);
        #endregion

    }
}
